/***********************************************************************************************************************
 * ############################################# Application AdewebLite #############################################
 * AdewebLite Android est une application permettant de consulter des emplois du temps fournis par l'université UHP
 * avec ou sans connexion internet (informations gardées en mémoire à chaque synchronisation). Et utilisant la web
 * API ADE pour collecter les données.
 * @author Andrianjafintrimo Victor, Zanette Sébastien
 * 
 * Basée sur l'application du même nom, utilisant le flux RSS (données à traiter), de :
 * @author Schnell Michaël, Zanette Sébastien
 * **********************************************************************************************************************
 */

package fr.ul.ade.prime.model;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;

/**
 * Comparaison de 2 emplois du temps et interclassement par ordre croissant
 * d'id.
 * 
 * @author Zanette Sébastien, @author Andrianjafintrimo Victor
 */
public class GuidScheduleUpdater extends ScheduleUpdater {

	@SuppressWarnings("unused")
	private static final String TAG = GuidScheduleUpdater.class.getSimpleName();

	protected ArrayList<Lesson> oldLessons;

	/**
	 * Creer une instance de <code>GuidScheduleUpdater</code>.
	 */
	public GuidScheduleUpdater() {
		super();
	}// GuidScheduleUpdater()

	/**
	 * Comparaison de 2 emplois du temps, basé sur l'id des lessons.
	 * 
	 * @param oldS
	 *            ancien emploi du temps (dans la base de données).
	 * @param newS
	 *            emploi du temps récupéré
	 */
	@Override
	protected void compareS(Schedule oldS, Schedule newS) {
		this.insert.ensureCapacity(newS.getNLessons());
		this.update.ensureCapacity(oldS.getNLessons());
		this.delete.ensureCapacity(oldS.getNLessons());
		this.buildOldGuids(oldS);
		final String today = String.format("%tY/%<tm/%<td",
				Calendar.getInstance());
		final String now = String.format("%tH/%<tM", Calendar.getInstance());
		// StringBuilder s = new StringBuilder();
		// for(Lesson l : oldS) s.append(String.format(",%s",l.getGuid()));
		// Log.d(TAG, "OldGuids: "+s.toString());
		// s.delete(0, s.length());
		// for(Lesson l : newS) s.append(String.format(",%s",l.getGuid()));
		// Log.d(TAG, "NewGuids: "+s.toString());
		for (Lesson newLesson : newS) {
			String newGuid = newLesson.getGuid();
			// lesson is old => guid known
			int indexOf = this.indexOf(newGuid);
			if (indexOf != -1) {
				// lesson is changed => update
				Lesson oldLesson = GuidScheduleUpdater.getLesson(oldS, newGuid);
				if (!oldLesson.equals(newLesson)) {
					if (isClose(newLesson.getStartDateTime())) {
						this.recent.add(newLesson);
					}// if
					newLesson.setLessonId(oldLesson.getLessonId());

					// Log.d(TAG,
					// String.format("Old: (date, room) = ('%s', '%s')",
					// oldLesson.getDate(), oldLesson.getRoom())) ;
					// Log.d(TAG,
					// String.format("New: (date, room) = ('%s', '%s')",
					// newLesson.getDate(), newLesson.getRoom())) ;

					// change le statut de représentant le niveau de changement
					newLesson.setChange(oldLesson.getLevelChange(newLesson));
					if (newLesson.getChange() == Lesson.BIG_CHANGE) {
						newLesson.setHistory(oldLesson);
					}// if
					this.update.add(newLesson);
					newLesson.setType(oldLesson.getType());
				}// if
				this.removeId(indexOf);
			} else {
				// lesson is new => guid unknown
				// On vérifie pour la date pour éviter l'ajout de cours passés
				int dateCmp = newLesson.getDate().compareTo(today);
				if (dateCmp > 0
						|| (dateCmp == 0 && newLesson.getEndHour()
								.compareTo(now) > 0)) {
					this.insert.add(newLesson);
					if (isClose(newLesson.getStartDateTime())) {
						this.recent.add(newLesson);
					}// if
				}// if
			}// if
		}// for
			// The remaining lessons have to be removed
		for (Lesson lesson : this.oldLessons) {
			if (isClose(lesson.getStartDateTime())) {
				this.recent.add(lesson);
			}// if
			this.delete.add(lesson);
		}// for
		this.oldLessons = null;
//		Log.d("GuidScheduleUpdater", String
//				.format("%s: (I, U, D, R, ic) = (%d, %d, %d, %d, %b)",
//						Long.valueOf(oldS.getId()),
//						Integer.valueOf(this.insert.size()),
//						Integer.valueOf(this.update.size()),
//						Integer.valueOf(this.delete.size()),
//						Integer.valueOf(this.recent.size()),
//						Boolean.valueOf(this.importantChange())));
//		Log.d("GuidScheduleUpdater",
//				oldS.getId() + ": R = " + this.recent.toString());
	}// compareS(Schedule, Schedule)

	/**
	 * Construit une liste d'emploi du temps par ordre croissant d'id grâce au
	 * tri par insertion.
	 * 
	 * @param schedule
	 *            emploi du temps
	 */
	protected void buildOldGuids(Schedule schedule) {
		this.oldLessons = new ArrayList<Lesson>(schedule.getNLessons());
		if (schedule.getNLessons() == 0) {
			return;
		}// if
		Iterator<Lesson> iterator = schedule.iterator();
		this.oldLessons.add(iterator.next());
		while (iterator.hasNext()) {
			Lesson lesson = iterator.next();
			int insertPosition = this.oldLessons.size();
			String lessonId = lesson.getGuid();
			while ((insertPosition > 0)
					&& (this.oldLessons.get(insertPosition - 1).getGuid()
							.compareTo(lessonId) > 0)) {
				insertPosition--;
			}// while
			this.oldLessons.add(insertPosition, lesson);
		}// while
	}// buildOldIds(Schedule)

	/**
	 * Retourne l'indice de la liste du cours passé grâce à son id. Le recherche
	 * est dichotomique.
	 * 
	 * @param id
	 *            id du cours
	 * @return
	 */
	protected int indexOf(String id) {
		boolean found = false;
		int left = 0, right = this.oldLessons.size() - 1;
		int middle = 0;
		while ((left <= right) && !found) {
			middle = (left + right) / 2;
			String currentId = this.oldLessons.get(middle).getGuid();
			int c = currentId.compareTo(id);
			if (c == 0) {
				found = true;
			} else if (c < 0) {
				left = middle + 1;
			} else/* c > 0 */{
				right = middle - 1;
			}// if
		}// while

		if (found) {
			return middle;
		}// if
		return -1;
	}// isOldId(long)

	/**
	 * Supprime un element de la liste de cours (cours de la BD).
	 * 
	 * @param removedPosition
	 */
	protected void removeId(int removedPosition) {
		this.oldLessons.remove(removedPosition);
	}// removeId(long)

	/**
	 * Retourne le cours identifié par l'id en paramètre.
	 * 
	 * @param schedule
	 *            emploi du temps
	 * @param lessonguid
	 *            id du cours
	 * @return cours identifié par l'id, null si pas de resultat
	 */
	protected static Lesson getLesson(Schedule schedule, String lessonguid) {
		for (Lesson lesson : schedule) {
			if (lesson.getGuid().equals(lessonguid)
			/* && (lesson.getScheduleId() == schedule.getId()) */) {
				return lesson;
			}// if
		}// for
		return null;
	}// getLesson(Schedule schedule, long)

}// class GuidScheduleUpdater